-module(ai_api).
-include("btree.hrl").

-export([
    run/1
    , event/2
    , get_tree/1
    , set_tree/1
]).

%% 运行某组检查，作为ai运行入口，定期循环执行即可
-spec run(node_id() | #bt{}) -> #bt{}.
run(Group) when is_integer(Group) ->
    Tree = run(get_tree(Group)),
    set_tree(Tree);
run(#bt{status = Status} = Tree) ->
    Events = maps:get(event, Status, []),
    Tree1 = lists:foldl(
        fun(Event, AccTree) ->
            Listen = maps:get({listen, postponed, Event}, Status, []),
            run_event(Listen, AccTree)
        end, Tree, Events),

    Tree2 = Tree1#bt{status = maps:remove(event, Status)},

    case is_record(Tree2#bt.result, bn) of
        true ->
            bnode_api:forward(Tree2, Tree2#bt.result);
        false ->
            bnode_api:forward(Tree2, Tree2#bt.entry)
    end.

%% 触发事件
event(G, Event) when is_integer(G) ->
    Tree = event(get_tree(G), Event),
    set_tree(Tree);
event(#bt{status = Status} = Tree, Event) ->
    Events = maps:get(event, Status, []),
    Events2 = lists:reverse([Event | Events]),
    Status2 = maps:put(event, Events2, Status),
    Tree1 = Tree#bt{status = Status2},

    Listen = maps:get({listen, immediate, Event}, Status, []),
    run_event(Listen, Tree1).

run_event([NodeID | T], Tree) ->
    Tree2 = bnode_api:forward(Tree, NodeID),
    run_event(T, Tree2);
run_event([], Tree) ->
    Tree.


get_tree(Group) ->
    gen_btree:get_tree(Group).

set_tree(Tree) ->
    gen_btree:set_tree(Tree).